From d3143da37731cf38df63a22c4d0c848c15062bd0 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Thu, 24 May 2001 16:04:22 +0000 Subject: [PATCH] updates. --- apps/irssi/COPYING | 340 ++++++++++ apps/irssi/src/silc/core/clientutil.c | 860 ++++++++++++++++++++++---- apps/irssi/src/silc/core/clientutil.h | 48 +- apps/irssi/src/silc/core/silc-core.c | 817 +++++++++++++----------- apps/irssi/src/silc/silc.c | 4 - 5 files changed, 1575 insertions(+), 494 deletions(-) create mode 100644 apps/irssi/COPYING delete mode 100644 apps/irssi/src/silc/silc.c diff --git a/apps/irssi/COPYING b/apps/irssi/COPYING new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/apps/irssi/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/apps/irssi/src/silc/core/clientutil.c b/apps/irssi/src/silc/core/clientutil.c index a9b0434e..1bcc9c8b 100644 --- a/apps/irssi/src/silc/core/clientutil.c +++ b/apps/irssi/src/silc/core/clientutil.c @@ -1,157 +1,771 @@ /* - clientutil.c : irssi - Copyright (C) 2000 Timo Sirainen + client.c - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + Author: Pekka Riikonen - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + Copyright (C) 1997 - 2000 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* $Id$ */ + +#include "clientincludes.h" + +/* Routine used to print lines to window. This can split the + line neatly if a word would overlap the line. */ + +void silc_print_to_window(WINDOW *win, char *message) +{ + int str_len, len; + + str_len = strlen(message); + + if (str_len > COLS - 1) { + /* Split overlapping words to next line */ + /* XXX In principal this is wrong as this modifies the original + string as it replaces the last ' ' with '\n'. This could be done + with little more work so that it would not replace anything. */ + len = COLS - 1; + while (1) { -#include "module.h" + while (len && message[len] != ' ') + len--; -#include "silc-servers.h" + if (!len) + break; -/* Verifies received public key. If user decides to trust the key it is - saved as trusted server key for later use. If user does not trust the - key this returns FALSE. */ + message[len] = '\n'; + len += COLS - 1; + if (len > str_len) + break; + } + } + + wprintw(win, "%s", message); + wrefresh(win); +} -int silc_client_verify_server_key(SILC_SERVER_REC *server, - unsigned char *pk, unsigned int pk_len, - SilcSKEPKType pk_type) +/* Prints message to the screen. This is used to print the messages + user is typed and message that came on channels. */ + +void silc_print(SilcClient client, char *msg, ...) { - char filename[256]; - char file[256]; - char *hostname, *fingerprint; - struct stat st; + va_list vp; + char message[2048]; + SilcClientInternal app = client->application; + + memset(message, 0, sizeof(message)); + strncat(message, "\n ", 2); + + va_start(vp, msg); + vsprintf(message + 1, msg, vp); + va_end(vp); + + /* Print the message */ + silc_print_to_window(app->screen->output_win[0], message); +} + +/* Returns user's mail path */ + +char *silc_get_mail_path() +{ + char pathbuf[MAXPATHLEN]; + char *path; + +#ifndef _PATH_MAILDIR +#define _PATH_MAILDIR "/var/mail" +#endif + + path = getenv("MAIL"); + if (path) { + strncpy(pathbuf, path, strlen(path)); + } else { + strcpy(pathbuf, _PATH_MAILDIR); + strcat(pathbuf, "/"); + strcat(pathbuf, silc_get_username()); + } + + return strdup(pathbuf); +} + +/* gets the number of the user's mails, if possible */ + +int silc_get_number_of_emails() +{ + FILE *tl; + int num = 0; + char *filename; + char data[1024]; + + filename = silc_get_mail_path(); + + tl = fopen(filename, "r"); + if (!tl) { + fprintf(stderr, "Couldn't open mail file (%s).\n", filename); + } else { + while((fscanf(tl, "%s", data)) != EOF) { + if(!strcmp(data, "From:")) + num++; + } + + fclose(tl); + } + + return num; +} + +/* Returns time til next minute changes. Used to update the clock when + needed. */ + +int silc_client_time_til_next_min() +{ + time_t curtime; + struct tm *min; + + curtime = time(0); + min = localtime(&curtime); + + return 60 - min->tm_sec; +} + +/* Asks yes/no from user on the input line. Returns TRUE on "yes" and + FALSE on "no". */ + +int silc_client_ask_yes_no(SilcClient client, char *prompt) +{ + SilcClientInternal app = (SilcClientInternal)client->application; + char answer[4]; + int ret; + + again: + silc_screen_input_reset(app->screen); + + /* Print prompt */ + wattroff(app->screen->input_win, A_INVIS); + silc_screen_input_print_prompt(app->screen, prompt); + + /* Get string */ + memset(answer, 0, sizeof(answer)); + echo(); + wgetnstr(app->screen->input_win, answer, sizeof(answer)); + if (!strncasecmp(answer, "yes", strlen(answer)) || + !strncasecmp(answer, "y", strlen(answer))) { + ret = TRUE; + } else if (!strncasecmp(answer, "no", strlen(answer)) || + !strncasecmp(answer, "n", strlen(answer))) { + ret = FALSE; + } else { + silc_say(client, app->conn, "Type yes or no"); + goto again; + } + noecho(); + + silc_screen_input_reset(app->screen); + + return ret; +} + +/* Lists supported (builtin) ciphers */ + +void silc_client_list_ciphers() +{ + char *ciphers = silc_cipher_get_supported(); + fprintf(stdout, "%s\n", ciphers); + silc_free(ciphers); +} + +/* Lists supported (builtin) hash functions */ + +void silc_client_list_hash_funcs() +{ + char *hash = silc_hash_get_supported(); + fprintf(stdout, "%s\n", hash); + silc_free(hash); +} + +/* Lists supported PKCS algorithms */ + +void silc_client_list_pkcs() +{ + char *pkcs = silc_pkcs_get_supported(); + fprintf(stdout, "%s\n", pkcs); + silc_free(pkcs); +} + +/* Displays input prompt on command line and takes input data from user */ + +char *silc_client_get_input(const char *prompt) +{ + char input[2048]; + int fd; + + fd = open("/dev/tty", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "silc: %s\n", strerror(errno)); + return NULL; + } + + memset(input, 0, sizeof(input)); + + printf("%s", prompt); + fflush(stdout); + + if ((read(fd, input, sizeof(input))) < 0) { + fprintf(stderr, "silc: %s\n", strerror(errno)); + return NULL; + } + + if (strlen(input) <= 1) + return NULL; + + if (strchr(input, '\n')) + *strchr(input, '\n') = '\0'; + + return strdup(input); +} + +/* Displays prompt on command line and takes passphrase with echo + off from user. */ + +char *silc_client_get_passphrase(const char *prompt) +{ +#if 0 + char input[2048]; + char *ret; + int fd; + struct termios to; + struct termios to_old; + + fd = open("/dev/tty", O_RDONLY); + if (fd < 0) { + fprintf(stderr, "silc: %s\n", strerror(errno)); + return NULL; + } + + signal(SIGINT, SIG_IGN); + + /* Get terminal info */ + tcgetattr(fd, &to); + to_old = to; + + /* Echo OFF */ + to.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); + tcsetattr(fd, TCSANOW, &to); + + memset(input, 0, sizeof(input)); + + printf("%s", prompt); + fflush(stdout); + + if ((read(fd, input, sizeof(input))) < 0) { + fprintf(stderr, "silc: %s\n", strerror(errno)); + return NULL; + } + + if (strlen(input) <= 1) { + tcsetattr(fd, TCSANOW, &to_old); + return NULL; + } + + if (strchr(input, '\n')) + *strchr(input, '\n') = '\0'; + + /* Restore old terminfo */ + tcsetattr(fd, TCSANOW, &to_old); + signal(SIGINT, SIG_DFL); + + ret = silc_calloc(strlen(input), sizeof(char)); + memcpy(ret, input, strlen(input)); + memset(input, 0, sizeof(input)); + return ret; +#else + return NULL; +#endif +} + +/* Returns identifier string for public key generation. */ + +char *silc_client_create_identifier() +{ + char *username = NULL, *realname = NULL; + char hostname[256], email[256]; + + /* Get realname */ + realname = silc_get_real_name(); + + /* Get hostname */ + memset(hostname, 0, sizeof(hostname)); + gethostname(hostname, sizeof(hostname)); + + /* Get username (mandatory) */ + username = silc_get_username(); + if (!username) + return NULL; + + /* Create default email address, whether it is right or not */ + snprintf(email, sizeof(email), "%s@%s", username, hostname); + + return silc_pkcs_encode_identifier(username, hostname, realname, email, + NULL, NULL); +} + +/* Creates new public key and private key pair. This is used only + when user wants to create new key pair from command line. */ + +int silc_client_create_key_pair(char *pkcs_name, int bits, + char *public_key, char *private_key, + char *identifier, + SilcPublicKey *ret_pub_key, + SilcPrivateKey *ret_prv_key) +{ + SilcPKCS pkcs; + SilcPublicKey pub_key; + SilcPrivateKey prv_key; + SilcRng rng; + unsigned char *key; + uint32 key_len; + char line[256]; + char *pkfile = NULL, *prvfile = NULL; + + if (!pkcs_name || !public_key || !private_key) + printf("\ +New pair of keys will be created. Please, answer to following questions.\n\ +"); - hostname = server->connrec->address; + if (!pkcs_name) { + again_name: + pkcs_name = + silc_client_get_input("PKCS name (l to list names) [rsa]: "); + if (!pkcs_name) + pkcs_name = strdup("rsa"); - if (pk_type != SILC_SKE_PK_TYPE_SILC) { - //silc_say(client, "We don't support server %s key type", hostname); + if (*pkcs_name == 'l' || *pkcs_name == 'L') { + silc_client_list_pkcs(); + silc_free(pkcs_name); + goto again_name; + } + } + + if (!silc_pkcs_is_supported(pkcs_name)) { + fprintf(stderr, "Unknown PKCS `%s'", pkcs_name); return FALSE; } + if (!bits) { + char *length = NULL; + length = + silc_client_get_input("Key length in bits [1024]: "); + if (!length) + bits = 1024; + else + bits = atoi(length); + } + + if (!identifier) { + char *def = silc_client_create_identifier(); + + memset(line, 0, sizeof(line)); + if (def) + snprintf(line, sizeof(line), "Identifier [%s]: ", def); + else + snprintf(line, sizeof(line), + "Identifier (eg. UN=jon, HN=jon.dummy.com, " + "RN=Jon Johnson, E=jon@dummy.com): "); + + while (!identifier) { + identifier = silc_client_get_input(line); + if (!identifier && def) + identifier = strdup(def); + } + + if (def) + silc_free(def); + } + + rng = silc_rng_alloc(); + silc_rng_init(rng); + silc_rng_global_init(rng); + + if (!public_key) { + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "Public key filename [%s] ", + SILC_CLIENT_PUBLIC_KEY_NAME); + pkfile = silc_client_get_input(line); + if (!pkfile) + pkfile = SILC_CLIENT_PUBLIC_KEY_NAME; + } else { + pkfile = public_key; + } + + if (!private_key) { + memset(line, 0, sizeof(line)); + snprintf(line, sizeof(line), "Public key filename [%s] ", + SILC_CLIENT_PRIVATE_KEY_NAME); + prvfile = silc_client_get_input(line); + if (!prvfile) + prvfile = SILC_CLIENT_PRIVATE_KEY_NAME; + } else { + prvfile = private_key; + } + + /* Generate keys */ + silc_pkcs_alloc(pkcs_name, &pkcs); + pkcs->pkcs->init(pkcs->context, bits, rng); + + /* Save public key into file */ + key = silc_pkcs_get_public_key(pkcs, &key_len); + pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier, + key, key_len); + silc_pkcs_save_public_key(pkfile, pub_key, SILC_PKCS_FILE_PEM); + if (ret_pub_key) + *ret_pub_key = pub_key; + + memset(key, 0, sizeof(key_len)); + silc_free(key); + + /* Save private key into file */ + key = silc_pkcs_get_private_key(pkcs, &key_len); + prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len); + + silc_pkcs_save_private_key(prvfile, prv_key, NULL, SILC_PKCS_FILE_BIN); + if (ret_prv_key) + *ret_prv_key = prv_key; + + printf("Public key has been saved into `%s'.\n", pkfile); + printf("Private key has been saved into `%s'.\n", prvfile); + printf("Press to continue...\n"); + getchar(); + + memset(key, 0, sizeof(key_len)); + silc_free(key); + + silc_rng_free(rng); + silc_pkcs_free(pkcs); + + return TRUE; +} + +/* This checks stats for various SILC files and directories. First it + checks if ~/.silc directory exist and is owned by the correct user. If + it doesn't exist, it will create the directory. After that it checks if + user's Public and Private key files exists and that they aren't expired. + If they doesn't exist or they are expired, they will be (re)created + after return. */ + +int silc_client_check_silc_dir() +{ + char filename[256], file_public_key[256], file_private_key[256]; + char servfilename[256], clientfilename[256]; + char *identifier; + struct stat st; + struct passwd *pw; + int firstime = FALSE; + time_t curtime, modtime; + + SILC_LOG_DEBUG(("Checking ~./silc directory")); + memset(filename, 0, sizeof(filename)); - memset(file, 0, sizeof(file)); - snprintf(file, sizeof(file) - 1, "serverkey_%s_%d.pub", hostname, - server->connrec->port); - snprintf(filename, sizeof(filename) - 1, "%s/.silc/serverkeys/%s", - g_get_home_dir(), file); - - /* Check wheter this key already exists */ - if (stat(filename, &st) < 0) { - - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - /*silc_say(client, "Received server %s public key", hostname); - silc_say(client, "Fingerprint for the server %s key is", hostname); - silc_say(client, "%s", fingerprint);*/ - silc_free(fingerprint); - - /* Ask user to verify the key and save it */ - /*if (silc_client_ask_yes_no(client, - "Would you like to accept the key (y/n)? "))*/ - { - /* Save the key for future checking */ - silc_pkcs_save_public_key_data(filename, pk, pk_len, - SILC_PKCS_FILE_PEM); - return TRUE; + memset(file_public_key, 0, sizeof(file_public_key)); + memset(file_private_key, 0, sizeof(file_private_key)); + + pw = getpwuid(getuid()); + if (!pw) { + fprintf(stderr, "silc: %s\n", strerror(errno)); + return FALSE; + } + + identifier = silc_client_create_identifier(); + + /* We'll take home path from /etc/passwd file to be sure. */ + snprintf(filename, sizeof(filename) - 1, "%s/.silc/", pw->pw_dir); + snprintf(servfilename, sizeof(servfilename) - 1, "%s/.silc/serverkeys", + pw->pw_dir); + snprintf(clientfilename, sizeof(clientfilename) - 1, "%s/.silc/clientkeys", + pw->pw_dir); + + /* + * Check ~/.silc directory + */ + if ((stat(filename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((mkdir(filename, 0755)) == -1) { + fprintf(stderr, "Couldn't create `%s' directory\n", filename); + return FALSE; + } + + /* Directory was created. First time running SILC */ + firstime = TRUE; + } else { + fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n", + filename); + return FALSE; } + } else { + fprintf(stderr, "%s\n", strerror(errno)); + return FALSE; + } } else { - /* The key already exists, verify it. */ - SilcPublicKey public_key; - unsigned char *encpk; - unsigned int encpk_len; - - /* Load the key file */ - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_PEM)) - if (!silc_pkcs_load_public_key(filename, &public_key, - SILC_PKCS_FILE_BIN)) { - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - /*silc_say(client, "Received server %s public key", hostname); - silc_say(client, "Fingerprint for the server %s key is", hostname); - silc_say(client, "%s", fingerprint);*/ - silc_free(fingerprint); - /*silc_say(client, "Could not load your local copy of the server %s key", - hostname); - if (silc_client_ask_yes_no(client, - "Would you like to accept the key anyway (y/n)? "))*/ - { - /* Save the key for future checking */ - unlink(filename); - silc_pkcs_save_public_key_data(filename, pk, pk_len, - SILC_PKCS_FILE_PEM); - return TRUE; - } - + + /* Check the owner of the dir */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + fprintf(stderr, "You don't seem to own `%s' directory\n", + filename); + return FALSE; + } + + /* Check the permissions of the dir */ + if ((st.st_mode & 0777) != 0755) { + if ((chmod(filename, 0755)) == -1) { + fprintf(stderr, "Permissions for `%s' directory must be 0755\n", + filename); return FALSE; } + } + } + + /* + * Check ~./silc/serverkeys directory + */ + if ((stat(servfilename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((mkdir(servfilename, 0755)) == -1) { + fprintf(stderr, "Couldn't create `%s' directory\n", servfilename); + return FALSE; + } + } else { + fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n", + servfilename); + return FALSE; + } + } else { + fprintf(stderr, "%s\n", strerror(errno)); + return FALSE; + } + } - /* Encode the key data */ - encpk = silc_pkcs_public_key_encode(public_key, &encpk_len); - if (!encpk) { - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - /*silc_say(client, "Received server %s public key", hostname); - silc_say(client, "Fingerprint for the server %s key is", hostname); - silc_say(client, "%s", fingerprint);*/ - silc_free(fingerprint); - /*silc_say(client, "Your local copy of the server %s key is malformed", - hostname); - if (silc_client_ask_yes_no(client, - "Would you like to accept the key anyway (y/n)? "))*/ - { - /* Save the key for future checking */ - unlink(filename); - silc_pkcs_save_public_key_data(filename, pk, pk_len, - SILC_PKCS_FILE_PEM); - return TRUE; + /* + * Check ~./silc/clientkeys directory + */ + if ((stat(clientfilename, &st)) == -1) { + /* If dir doesn't exist */ + if (errno == ENOENT) { + if (pw->pw_uid == geteuid()) { + if ((mkdir(clientfilename, 0755)) == -1) { + fprintf(stderr, "Couldn't create `%s' directory\n", clientfilename); + return FALSE; } + } else { + fprintf(stderr, "Couldn't create `%s' directory due to a wrong uid!\n", + clientfilename); + return FALSE; + } + } else { + fprintf(stderr, "%s\n", strerror(errno)); + return FALSE; + } + } + + /* + * Check Public and Private keys + */ + snprintf(file_public_key, sizeof(file_public_key) - 1, "%s%s", + filename, SILC_CLIENT_PUBLIC_KEY_NAME); + snprintf(file_private_key, sizeof(file_private_key) - 1, "%s%s", + filename, SILC_CLIENT_PRIVATE_KEY_NAME); + + /* If running SILC first time */ + if (firstime) { + fprintf(stdout, "Running SILC for the first time\n"); + silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, + SILC_CLIENT_DEF_PKCS_LEN, + file_public_key, file_private_key, + identifier, NULL, NULL); + return TRUE; + } + + if ((stat(file_public_key, &st)) == -1) { + /* If file doesn't exist */ + if (errno == ENOENT) { + fprintf(stdout, "Your public key doesn't exist\n"); + silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, + SILC_CLIENT_DEF_PKCS_LEN, + file_public_key, + file_private_key, identifier, NULL, NULL); + } else { + fprintf(stderr, "%s\n", strerror(errno)); + return FALSE; + } + } + if ((stat(file_private_key, &st)) == -1) { + /* If file doesn't exist */ + if (errno == ENOENT) { + fprintf(stdout, "Your private key doesn't exist\n"); + silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, + SILC_CLIENT_DEF_PKCS_LEN, + file_public_key, + file_private_key, identifier, NULL, NULL); + } else { + fprintf(stderr, "%s\n", strerror(errno)); return FALSE; } + } + + /* Check the owner of the public key */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + fprintf(stderr, "You don't seem to own your public key!?\n"); + return FALSE; + } + + /* Check the owner of the private key */ + if (st.st_uid != 0 && st.st_uid != pw->pw_uid) { + fprintf(stderr, "You don't seem to own your private key!?\n"); + return FALSE; + } + + /* Check the permissions for the private key */ + if ((st.st_mode & 0777) != 0600) { + fprintf(stderr, "Wrong permissions in your private key file `%s'!\n" + "Trying to change them ... ", file_private_key); + if ((chmod(file_private_key, 0600)) == -1) { + fprintf(stderr, + "Failed to change permissions for private key file!\n" + "Permissions for your private key file must be 0600.\n"); + return FALSE; + } + fprintf(stderr, "Done.\n\n"); + } - if (memcmp(encpk, pk, encpk_len)) { - fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); - /*silc_say(client, "Received server %s public key", hostname); - silc_say(client, "Fingerprint for the server %s key is", hostname); - silc_say(client, "%s", fingerprint);*/ - silc_free(fingerprint); - /*silc_say(client, "Server %s key does not match with your local copy", - hostname); - silc_say(client, "It is possible that the key has expired or changed"); - silc_say(client, "It is also possible that some one is performing " - "man-in-the-middle attack");*/ - - /* Ask user to verify the key and save it */ - /*if (silc_client_ask_yes_no(client, - "Would you like to accept the key anyway (y/n)? "))*/ - { - /* Save the key for future checking */ - unlink(filename); - silc_pkcs_save_public_key_data(filename, pk, pk_len, - SILC_PKCS_FILE_PEM); - return TRUE; - } + /* See if the key has expired. */ + modtime = st.st_mtime; /* last modified */ + curtime = time(0) - modtime; + + /* 86400 is seconds in a day. */ + if (curtime >= (86400 * SILC_CLIENT_KEY_EXPIRES)) { + fprintf(stdout, + "--------------------------------------------------\n" + "Your private key has expired and needs to be\n" + "recreated. This will be done automatically now.\n" + "Your new key will expire in %d days from today.\n" + "--------------------------------------------------\n", + SILC_CLIENT_KEY_EXPIRES); + + silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, + SILC_CLIENT_DEF_PKCS_LEN, + file_public_key, + file_private_key, identifier, NULL, NULL); + } + + if (identifier) + silc_free(identifier); + + return TRUE; +} + +/* Loads public and private key from files. */ + +int silc_client_load_keys(SilcClient client) +{ + char filename[256]; + struct passwd *pw; + + SILC_LOG_DEBUG(("Loading public and private keys")); + + pw = getpwuid(getuid()); + if (!pw) + return FALSE; + + memset(filename, 0, sizeof(filename)); + snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", + pw->pw_dir, SILC_CLIENT_PRIVATE_KEY_NAME); + + if (silc_pkcs_load_private_key(filename, &client->private_key, + SILC_PKCS_FILE_BIN) == FALSE) + if (silc_pkcs_load_private_key(filename, &client->private_key, + SILC_PKCS_FILE_PEM) == FALSE) + return FALSE; + + memset(filename, 0, sizeof(filename)); + snprintf(filename, sizeof(filename) - 1, "%s/.silc/%s", + pw->pw_dir, SILC_CLIENT_PUBLIC_KEY_NAME); - //silc_say(client, "Will not accept server %s key", hostname); + if (silc_pkcs_load_public_key(filename, &client->public_key, + SILC_PKCS_FILE_PEM) == FALSE) + if (silc_pkcs_load_public_key(filename, &client->public_key, + SILC_PKCS_FILE_BIN) == FALSE) + return FALSE; + + return TRUE; +} + +/* Dumps the public key on screen. Used from the command line option. */ + +int silc_client_show_key(char *keyfile) +{ + SilcPublicKey public_key; + SilcPublicKeyIdentifier ident; + char *fingerprint; + unsigned char *pk; + uint32 pk_len; + SilcPKCS pkcs; + int key_len = 0; + + if (silc_pkcs_load_public_key(keyfile, &public_key, + SILC_PKCS_FILE_PEM) == FALSE) + if (silc_pkcs_load_public_key(keyfile, &public_key, + SILC_PKCS_FILE_BIN) == FALSE) { + fprintf(stderr, "Could not load public key file `%s'\n", keyfile); return FALSE; } - /* Local copy matched */ - return TRUE; + ident = silc_pkcs_decode_identifier(public_key->identifier); + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + fingerprint = silc_hash_fingerprint(NULL, pk, pk_len); + + if (silc_pkcs_alloc(public_key->name, &pkcs)) { + key_len = silc_pkcs_public_key_set(pkcs, public_key); + silc_pkcs_free(pkcs); } - //silc_say(client, "Will not accept server %s key", hostname); - return FALSE; + printf("Public key file : %s\n", keyfile); + printf("Algorithm : %s\n", public_key->name); + if (key_len) + printf("Key length (bits) : %d\n", key_len); + if (ident->realname) + printf("Real name : %s\n", ident->realname); + if (ident->username) + printf("Username : %s\n", ident->username); + if (ident->host) + printf("Hostname : %s\n", ident->host); + if (ident->email) + printf("Email : %s\n", ident->email); + if (ident->org) + printf("Organization : %s\n", ident->org); + if (ident->country) + printf("Country : %s\n", ident->country); + printf("Fingerprint (SHA1) : %s\n", fingerprint); + + fflush(stdout); + + silc_free(fingerprint); + silc_free(pk); + silc_pkcs_public_key_free(public_key); + silc_pkcs_free_identifier(ident); + + return TRUE; } diff --git a/apps/irssi/src/silc/core/clientutil.h b/apps/irssi/src/silc/core/clientutil.h index 4af7425d..b4215198 100644 --- a/apps/irssi/src/silc/core/clientutil.h +++ b/apps/irssi/src/silc/core/clientutil.h @@ -1,8 +1,46 @@ -#ifndef __CLIENTUTIL_H -#define __CLIENTUTIL_H +/* -int silc_client_verify_server_key(SILC_SERVER_REC *server, - unsigned char *pk, unsigned int pk_len, - SilcSKEPKType pk_type); + client.h + + Author: Pekka Riikonen + + Copyright (C) 1997 - 2000 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef CLIENTUTIL_H +#define CLIENTUTIL_H + +/* Prototypes */ +void silc_print_to_window(WINDOW *win, char *message); +void silc_print(SilcClient client, char *msg, ...); +char *silc_get_mail_path(); +int silc_get_number_of_emails(); +int silc_client_time_til_next_min(); +int silc_client_ask_yes_no(SilcClient client, char *prompt); +char *silc_client_get_input(const char *prompt); +char *silc_client_get_passphrase(const char *prompt); +void silc_client_list_ciphers(); +void silc_client_list_hash_funcs(); +void silc_client_list_pkcs(); +char *silc_client_create_identifier(); +int silc_client_create_key_pair(char *pkcs_name, int bits, + char *public_key, char *private_key, + char *identifier, + SilcPublicKey *ret_pub_key, + SilcPrivateKey *ret_prv_key); +int silc_client_check_silc_dir(); +int silc_client_load_keys(SilcClient client); +int silc_client_show_key(char *keyfile); #endif diff --git a/apps/irssi/src/silc/core/silc-core.c b/apps/irssi/src/silc/core/silc-core.c index 7afa379b..98068d3a 100644 --- a/apps/irssi/src/silc/core/silc-core.c +++ b/apps/irssi/src/silc/core/silc-core.c @@ -1,3 +1,23 @@ +/* + + silc-core.c + + Author: Pekka Riikonen + + Copyright (C) 2001 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + #include "module.h" #include "chat-protocols.h" @@ -16,126 +36,158 @@ #include "fe-common/core/printtext.h" #include "fe-common/core/fe-channels.h" -#define SILC_CLIENT_PUBLIC_KEY_NAME "public_key.pub" -#define SILC_CLIENT_PRIVATE_KEY_NAME "private_key.prv" - -#define SILC_CLIENT_DEF_PKCS "rsa" -#define SILC_CLIENT_DEF_PKCS_LEN 1024 - -SilcClient silc_client; -const char *silc_version_string = SILC_PROTOCOL_VERSION_STRING; +/* Command line option variables */ +static char *opt_server = NULL; +static int opt_port = 0; +static char *opt_nickname = NULL; +static char *opt_channel = NULL; +static char *opt_cipher = NULL; +static char *opt_public_key = NULL; +static char *opt_private_key = NULL; +static char *opt_config_file = NULL; +static bool opt_no_silcrc = FALSE; + +static bool opt_create_keypair = FALSE; +static char *opt_pkcs = NULL; +static char *opt_keyfile = NULL; +static int opt_bits = 0; static int idletag; - +static SilcClient silc_client; extern SilcClientOperations ops; static void silc_say(SilcClient client, SilcClientConnection conn, char *msg, ...) { - SILC_SERVER_REC *server; - va_list va; - char *str; - - server = conn == NULL ? NULL : conn->context; - - va_start(va, msg); - str = g_strdup_vprintf(msg, va); - printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str); - g_free(str); - va_end(va); + SILC_SERVER_REC *server; + va_list va; + char *str; + + server = conn == NULL ? NULL : conn->context; + + va_start(va, msg); + str = g_strdup_vprintf(msg, va); + printtext(server, "#silc", MSGLEVEL_CRAP, "%s", str); + g_free(str); + va_end(va); } -static void silc_channel_message(SilcClient c, SilcClientConnection conn, - SilcClientEntry client, - SilcChannelEntry channel, char *msg) +/* Message for a channel. The `sender' is the nickname of the sender + received in the packet. The `channel_name' is the name of the channel. */ + +static void +silc_channel_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcChannelEntry channel, + SilcMessageFlags flags, char *msg) { - SILC_SERVER_REC *server; - SILC_NICK_REC *nick; - SILC_CHANNEL_REC *chanrec; - - server = conn == NULL ? NULL : conn->context; - chanrec = silc_channel_find_entry(server, channel); - - nick = client == NULL ? NULL : silc_nicklist_find(chanrec, client); - signal_emit("message public", 6, server, msg, - nick == NULL ? "(unknown)" : nick->nick, - nick == NULL ? NULL : nick->host, - chanrec->name, nick); + SILC_SERVER_REC *server; + SILC_NICK_REC *nick; + SILC_CHANNEL_REC *chanrec; + + server = conn == NULL ? NULL : conn->context; + chanrec = silc_channel_find_entry(server, channel); + + nick = silc_nicklist_find(chanrec, sender); + signal_emit("message public", 6, server, msg, + nick == NULL ? "(unknown)" : nick->nick, + nick == NULL ? NULL : nick->host, + chanrec->name, nick); } -static void silc_private_message(SilcClient c, SilcClientConnection conn, - SilcClientEntry client, char *msg) -{ - SILC_SERVER_REC *server; +/* Private message to the client. The `sender' is the nickname of the + sender received in the packet. */ - server = conn == NULL ? NULL : conn->context; - signal_emit("message private", 4, server, msg, - client == NULL ? "(unknown)" : client->nickname, - client == NULL ? NULL : client->username); +static void +silc_private_message(SilcClient client, SilcClientConnection conn, + SilcClientEntry sender, SilcMessageFlags flags, + char *msg) +{ + SILC_SERVER_REC *server; + + server = conn == NULL ? NULL : conn->context; + signal_emit("message private", 4, server, msg, + sender->nickname ? sender->nickname : "(unknown)", + sender->username ? sender->username : NULL); } +/* Notify message to the client. The notify arguments are sent in the + same order as servers sends them. The arguments are same as received + from the server except for ID's. If ID is received application receives + the corresponding entry to the ID. For example, if Client ID is received + application receives SilcClientEntry. Also, if the notify type is + for channel the channel entry is sent to application (even if server + does not send it). */ + typedef struct { - int type; - const char *name; + int type; + const char *name; } NOTIFY_REC; #define MAX_NOTIFY (sizeof(notifies)/sizeof(notifies[0])) static NOTIFY_REC notifies[] = { - { SILC_NOTIFY_TYPE_NONE, NULL }, - { SILC_NOTIFY_TYPE_INVITE, "invite" }, - { SILC_NOTIFY_TYPE_JOIN, "join" }, - { SILC_NOTIFY_TYPE_LEAVE, "leave" }, - { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" }, - { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" }, - { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" }, - { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" }, - { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" }, - { SILC_NOTIFY_TYPE_MOTD, "motd" } + { SILC_NOTIFY_TYPE_NONE, NULL }, + { SILC_NOTIFY_TYPE_INVITE, "invite" }, + { SILC_NOTIFY_TYPE_JOIN, "join" }, + { SILC_NOTIFY_TYPE_LEAVE, "leave" }, + { SILC_NOTIFY_TYPE_SIGNOFF, "signoff" }, + { SILC_NOTIFY_TYPE_TOPIC_SET, "topic" }, + { SILC_NOTIFY_TYPE_NICK_CHANGE, "nick" }, + { SILC_NOTIFY_TYPE_CMODE_CHANGE, "cmode" }, + { SILC_NOTIFY_TYPE_CUMODE_CHANGE, "cumode" }, + { SILC_NOTIFY_TYPE_MOTD, "motd" } }; static void silc_notify(SilcClient client, SilcClientConnection conn, - SilcNotifyType type, ...) + SilcNotifyType type, ...) { - SILC_SERVER_REC *server; - va_list va; - - server = conn == NULL ? NULL : conn->context; - va_start(va, type); - - if (type == SILC_NOTIFY_TYPE_NONE) { - /* some generic notice from server */ - printtext(server, NULL, MSGLEVEL_CRAP, "%s", - (char *) va_arg(va, char *)); - } else if (type < MAX_NOTIFY) { - /* send signal about the notify event */ - char signal[50]; - - g_snprintf(signal, sizeof(signal), "silc event %s", - notifies[type].name); - signal_emit(signal, 2, server, va); - } else { - /* unknown notify */ - printtext(server, NULL, MSGLEVEL_CRAP, - "Unknown notify %d", type); - } - va_end(va); + SILC_SERVER_REC *server; + va_list va; + + server = conn == NULL ? NULL : conn->context; + va_start(va, type); + + if (type == SILC_NOTIFY_TYPE_NONE) { + /* some generic notice from server */ + printtext(server, NULL, MSGLEVEL_CRAP, "%s", + (char *) va_arg(va, char *)); + } else if (type < MAX_NOTIFY) { + /* send signal about the notify event */ + char signal[50]; + + g_snprintf(signal, sizeof(signal), "silc event %s", + notifies[type].name); + signal_emit(signal, 2, server, va); + } else { + /* unknown notify */ + printtext(server, NULL, MSGLEVEL_CRAP, + "Unknown notify %d", type); + } + va_end(va); } -static void silc_connect(SilcClient client, SilcClientConnection conn, int success) -{ - SILC_SERVER_REC *server = conn->context; +/* Called to indicate that connection was either successfully established + or connecting failed. This is also the first time application receives + the SilcClientConnection objecet which it should save somewhere. */ - if (success) { - server->connected = TRUE; - signal_emit("event connected", 1, server); - } else { - server->connection_lost = TRUE; - server->conn->context = NULL; - server_disconnect(SERVER(server)); - } +static void +silc_connect(SilcClient client, SilcClientConnection conn, int success) +{ + SILC_SERVER_REC *server = conn->context; + + if (success) { + server->connected = TRUE; + signal_emit("event connected", 1, server); + } else { + server->connection_lost = TRUE; + server->conn->context = NULL; + server_disconnect(SERVER(server)); + } } -static void silc_disconnect(SilcClient client, SilcClientConnection conn) +/* Called to indicate that connection was disconnected to the server. */ + +static void +silc_disconnect(SilcClient client, SilcClientConnection conn) { SILC_SERVER_REC *server = conn->context; @@ -145,333 +197,374 @@ static void silc_disconnect(SilcClient client, SilcClientConnection conn) server_disconnect(SERVER(server)); } -static void silc_command(SilcClient client, SilcClientConnection conn, - SilcClientCommandContext cmd_context, int success, - SilcCommand command) +/* Command handler. This function is called always in the command function. + If error occurs it will be called as well. `conn' is the associated + client connection. `cmd_context' is the command context that was + originally sent to the command. `success' is FALSE if error occured + during command. `command' is the command being processed. It must be + noted that this is not reply from server. This is merely called just + after application has called the command. Just to tell application + that the command really was processed. */ + +static void +silc_command(SilcClient client, SilcClientConnection conn, + SilcClientCommandContext cmd_context, int success, + SilcCommand command) { } -static void silc_command_reply(SilcClient client, SilcClientConnection conn, - SilcCommandPayload cmd_payload, int success, - SilcCommand command, - SilcCommandStatus status, ...) +/* Command reply handler. This function is called always in the command reply + function. If error occurs it will be called as well. Normal scenario + is that it will be called after the received command data has been parsed + and processed. The function is used to pass the received command data to + the application. + + `conn' is the associated client connection. `cmd_payload' is the command + payload data received from server and it can be ignored. It is provided + if the application would like to re-parse the received command data, + however, it must be noted that the data is parsed already by the library + thus the payload can be ignored. `success' is FALSE if error occured. + In this case arguments are not sent to the application. `command' is the + command reply being processed. The function has variable argument list + and each command defines the number and type of arguments it passes to the + application (on error they are not sent). */ + +static void +silc_command_reply(SilcClient client, SilcClientConnection conn, + SilcCommandPayload cmd_payload, int success, + SilcCommand command, SilcCommandStatus status, ...) + { - SILC_SERVER_REC *server = conn->context; - SILC_CHANNEL_REC *chanrec; - va_list va; - - va_start(va, status); - - /*g_snprintf(signal, sizeof(signal), "silc command reply %s", - silc_commands[type]); - signal_emit(signal, 2, server, va);*/ - - switch(command) { - case SILC_COMMAND_JOIN: { - char *channel, *mode; - - channel = va_arg(va, char *); - (void)va_arg(va, SilcChannelEntry); - mode = silc_client_chmode(va_arg(va, unsigned int)); - - chanrec = silc_channel_find(server, channel); - if (chanrec != NULL && !success) - channel_destroy(CHANNEL(chanrec)); - else if (chanrec == NULL && success) - chanrec = silc_channel_create(server, channel, TRUE); - - g_free_not_null(chanrec->mode); - chanrec->mode = g_strdup(mode == NULL ? "" : mode); - signal_emit("channel mode changed", 1, chanrec); - break; - } - case SILC_COMMAND_NICK: { - SilcClientEntry client = va_arg(va, SilcClientEntry); - char *old; - - old = g_strdup(server->nick); - server_change_nick(SERVER(server), client->nickname); - nicklist_rename_unique(SERVER(server), - server->conn->local_entry, server->nick, - client, client->nickname); - - signal_emit("message own_nick", 4, - server, server->nick, old, ""); - g_free(old); - break; - } - case SILC_COMMAND_USERS: { - SilcChannelEntry channel; - SilcChannelUser user; - NICK_REC *ownnick; - - channel = va_arg(va, SilcChannelEntry); - chanrec = silc_channel_find_entry(server, channel); - if (chanrec == NULL) - break; - - silc_list_start(channel->clients); - while ((user = silc_list_get(channel->clients)) != NULL) - silc_nicklist_insert(chanrec, user, FALSE); - - ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry)); - nicklist_set_own(CHANNEL(chanrec), ownnick); - signal_emit("channel joined", 1, chanrec); - fe_channels_nicklist(CHANNEL(chanrec), - CHANNEL_NICKLIST_FLAG_ALL); - break; - } - } - - va_end(va); + SILC_SERVER_REC *server = conn->context; + SILC_CHANNEL_REC *chanrec; + va_list va; + + va_start(va, status); + + /*g_snprintf(signal, sizeof(signal), "silc command reply %s", + silc_commands[type]); + signal_emit(signal, 2, server, va);*/ + + switch(command) { + case SILC_COMMAND_JOIN: + { + char *channel, *mode; + uint32 modei; + SilcChannelEntry channel_entry; + + channel = va_arg(va, char *); + channel_entry = va_arg(va, SilcChannelEntry); + modei = va_arg(va, uint32); + mode = silc_client_chmode(modei, channel_entry); + + chanrec = silc_channel_find(server, channel); + if (chanrec != NULL && !success) + channel_destroy(CHANNEL(chanrec)); + else if (chanrec == NULL && success) + chanrec = silc_channel_create(server, channel, TRUE); + + g_free_not_null(chanrec->mode); + chanrec->mode = g_strdup(mode == NULL ? "" : mode); + signal_emit("channel mode changed", 1, chanrec); + break; + } + case SILC_COMMAND_NICK: + { + SilcClientEntry client = va_arg(va, SilcClientEntry); + char *old; + + old = g_strdup(server->nick); + server_change_nick(SERVER(server), client->nickname); + nicklist_rename_unique(SERVER(server), + server->conn->local_entry, server->nick, + client, client->nickname); + + signal_emit("message own_nick", 4, + server, server->nick, old, ""); + g_free(old); + break; + } + case SILC_COMMAND_USERS: + { + SilcChannelEntry channel; + SilcChannelUser user; + NICK_REC *ownnick; + + channel = va_arg(va, SilcChannelEntry); + chanrec = silc_channel_find_entry(server, channel); + if (chanrec == NULL) + break; + + silc_list_start(channel->clients); + while ((user = silc_list_get(channel->clients)) != NULL) + silc_nicklist_insert(chanrec, user, FALSE); + + ownnick = NICK(silc_nicklist_find(chanrec, conn->local_entry)); + nicklist_set_own(CHANNEL(chanrec), ownnick); + signal_emit("channel joined", 1, chanrec); + fe_channels_nicklist(CHANNEL(chanrec), + CHANNEL_NICKLIST_FLAG_ALL); + break; + } + } + + va_end(va); } -static int silc_verify_server_key(SilcClient client, SilcClientConnection conn, - unsigned char *pk, unsigned int pk_len, +/* Verifies received public key. If user decides to trust the key it is + saved as public server key for later use. If user does not trust the + key this returns FALSE. */ + +static int silc_verify_public_key(SilcClient client, + SilcClientConnection conn, + SilcSocketType conn_type, + unsigned char *pk, uint32 pk_len, SilcSKEPKType pk_type) { - return TRUE; + return TRUE; } +/* Asks passphrase from user on the input line. */ + static unsigned char *silc_ask_passphrase(SilcClient client, SilcClientConnection conn) { return NULL; } -static int silc_get_auth_method(SilcClient client, SilcClientConnection conn, - char *hostname, unsigned short port, - SilcProtocolAuthMeth *auth_meth, - unsigned char **auth_data, - unsigned int *auth_data_len) -{ - return FALSE; -} - -static void silc_failure(SilcClient client, SilcClientConnection conn, - SilcProtocol protocol, void *failure) +/* Find authentication method and authentication data by hostname and + port. The hostname may be IP address as well. The found authentication + method and authentication data is returned to `auth_meth', `auth_data' + and `auth_data_len'. The function returns TRUE if authentication method + is found and FALSE if not. `conn' may be NULL. */ + +static int +silc_get_auth_method(SilcClient client, SilcClientConnection conn, + char *hostname, uint16 port, + SilcProtocolAuthMeth *auth_meth, + unsigned char **auth_data, + uint32 *auth_data_len) { + return FALSE; } -static int key_agreement(SilcClient client, SilcClientConnection conn, - SilcClientEntry client_entry, char *hostname, - int port) -{ - return FALSE; -} +/* Notifies application that failure packet was received. This is called + if there is some protocol active in the client. The `protocol' is the + protocol context. The `failure' is opaque pointer to the failure + indication. Note, that the `failure' is protocol dependant and application + must explicitly cast it to correct type. Usually `failure' is 32 bit + failure type (see protocol specs for all protocol failure types). */ -SilcClientOperations ops = { - silc_say, - silc_channel_message, - silc_private_message, - silc_notify, - silc_command, - silc_command_reply, - silc_connect, - silc_disconnect, - silc_get_auth_method, - silc_verify_server_key, - silc_ask_passphrase, - silc_failure, - key_agreement -}; - -/* Loads public and private key from files. */ - -static void silc_client_create_key_pair(char *pkcs_name, int bits, - char *identifier, - SilcPublicKey *pub_key, - SilcPrivateKey *prv_key) +static void +silc_failure(SilcClient client, SilcClientConnection conn, + SilcProtocol protocol, void *failure) { - SilcPKCS pkcs; - SilcRng rng; - unsigned char *key; - unsigned int key_len; - - rng = silc_rng_alloc(); - silc_rng_init(rng); - silc_rng_global_init(rng); - - silc_pkcs_alloc(pkcs_name, &pkcs); - pkcs->pkcs->init(pkcs->context, bits, rng); - - /* Create public key */ - key = silc_pkcs_get_public_key(pkcs, &key_len); - *pub_key = silc_pkcs_public_key_alloc(pkcs->pkcs->name, identifier, - key, key_len); - - memset(key, 0, sizeof(key_len)); - silc_free(key); - - /* Create private key */ - key = silc_pkcs_get_private_key(pkcs, &key_len); - *prv_key = silc_pkcs_private_key_alloc(pkcs->pkcs->name, key, key_len); - - memset(key, 0, sizeof(key_len)); - silc_free(key); - - silc_rng_free(rng); - silc_pkcs_free(pkcs); + if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) { + SilcSKEStatus status = (SilcSKEStatus)failure; + + if (status == SILC_SKE_STATUS_BAD_VERSION) + silc_say(client, conn, + "You are running incompatible client version (it may be " + "too old or too new)"); + if (status == SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY) + silc_say(client, conn, "Server does not support your public key type"); + if (status == SILC_SKE_STATUS_UNKNOWN_GROUP) + silc_say(client, conn, + "Server does not support one of your proposed KE group"); + if (status == SILC_SKE_STATUS_UNKNOWN_CIPHER) + silc_say(client, conn, + "Server does not support one of your proposed cipher"); + if (status == SILC_SKE_STATUS_UNKNOWN_PKCS) + silc_say(client, conn, + "Server does not support one of your proposed PKCS"); + if (status == SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION) + silc_say(client, conn, + "Server does not support one of your proposed hash function"); + if (status == SILC_SKE_STATUS_UNKNOWN_HMAC) + silc_say(client, conn, + "Server does not support one of your proposed HMAC"); + if (status == SILC_SKE_STATUS_INCORRECT_SIGNATURE) + silc_say(client, conn, "Incorrect signature"); + } + + if (protocol->protocol->type == SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) { + uint32 err = (uint32)failure; + + if (err == SILC_AUTH_FAILED) + silc_say(client, conn, "Authentication failed"); + } } -static int read_keyfiles(SilcClient client, char *public_file, - char *private_file) +/* Asks whether the user would like to perform the key agreement protocol. + This is called after we have received an key agreement packet or an + reply to our key agreement packet. This returns TRUE if the user wants + the library to perform the key agreement protocol and FALSE if it is not + desired (application may start it later by calling the function + silc_client_perform_key_agreement). */ + +static int +silc_key_agreement(SilcClient client, SilcClientConnection conn, + SilcClientEntry client_entry, char *hostname, + int port, + SilcKeyAgreementCallback *completion, + void **context) { - struct stat statbuf; + char host[256]; - if (stat(public_file, &statbuf) != 0 || - stat(private_file, &statbuf) != 0) - return FALSE; + /* We will just display the info on the screen and return FALSE and user + will have to start the key agreement with a command. */ - if (!silc_pkcs_load_private_key(private_file, &client->private_key, - SILC_PKCS_FILE_BIN) && - !silc_pkcs_load_private_key(private_file, &client->private_key, - SILC_PKCS_FILE_PEM)) - return FALSE; + if (hostname) { + memset(host, 0, sizeof(host)); + snprintf(host, sizeof(host) - 1, "(%s on port %d)", hostname, port); + } - if (!silc_pkcs_load_public_key(public_file, &client->public_key, - SILC_PKCS_FILE_PEM) && - !silc_pkcs_load_public_key(public_file, &client->public_key, - SILC_PKCS_FILE_BIN)) - return FALSE; + silc_say(client, conn, "%s wants to perform key agreement %s", + client_entry->nickname, hostname ? host : ""); - return TRUE; -} - -static char *silc_create_identifier(SilcClient client) -{ - char hostname[256], *email, *ret; - - if (gethostname(hostname, sizeof(hostname)) != 0) - hostname[0] = '\0'; + *completion = NULL; + *context = NULL; - email = g_strdup_printf("%s@%s", client->username, hostname); - ret = silc_pkcs_encode_identifier(client->username, hostname, - client->realname, email, - NULL, NULL); - g_free(email); - return ret; + return FALSE; } -static int load_keys(SilcClient client) -{ - char *public_file, *private_file; - char *identifier; - - public_file = g_strdup_printf("%s/.irssi/%s", g_get_home_dir(), - SILC_CLIENT_PUBLIC_KEY_NAME); - private_file = g_strdup_printf("%s/.irssi/%s", g_get_home_dir(), - SILC_CLIENT_PRIVATE_KEY_NAME); - - if (!read_keyfiles(client, public_file, private_file)) { - /* couldn't read key files, recreate them */ - identifier = silc_create_identifier(client); - silc_client_create_key_pair(SILC_CLIENT_DEF_PKCS, - SILC_CLIENT_DEF_PKCS_LEN, - identifier, - &client->public_key, - &client->private_key); - silc_free(identifier); - - silc_pkcs_save_public_key(public_file, client->public_key, - SILC_PKCS_FILE_PEM); - silc_pkcs_save_private_key(private_file, client->private_key, - NULL, SILC_PKCS_FILE_BIN); - } - - g_free(public_file); - g_free(private_file); - return TRUE; -} +/* SILC client operations */ +SilcClientOperations ops = { + silc_say, + silc_channel_message, + silc_private_message, + silc_notify, + silc_command, + silc_command_reply, + silc_connect, + silc_disconnect, + silc_get_auth_method, + silc_verify_public_key, + silc_ask_passphrase, + silc_failure, + silc_key_agreement, +}; static int my_silc_scheduler(void) { - silc_schedule_one(0); - return 1; + silc_schedule_one(0); + return 1; } static CHATNET_REC *create_chatnet(void) { - return g_malloc0(sizeof(CHATNET_REC)); + return g_malloc0(sizeof(CHATNET_REC)); } static SERVER_SETUP_REC *create_server_setup(void) { - return g_malloc0(sizeof(SERVER_SETUP_REC)); + return g_malloc0(sizeof(SERVER_SETUP_REC)); } static CHANNEL_SETUP_REC *create_channel_setup(void) { - return g_malloc0(sizeof(CHANNEL_SETUP_REC)); + return g_malloc0(sizeof(CHANNEL_SETUP_REC)); } static SERVER_CONNECT_REC *create_server_connect(void) { - return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC)); + return g_malloc0(sizeof(SILC_SERVER_CONNECT_REC)); } -/* Command line option variables */ void silc_core_init(void) { - CHAT_PROTOCOL_REC *rec; - - silc_client = silc_client_alloc(&ops, NULL); - silc_client->username = g_strdup(settings_get_str("user_name")); - silc_client->hostname = silc_net_localhost(); - silc_client->realname = g_strdup(settings_get_str("real_name")); - - if (!load_keys(silc_client)) { - idletag = -1; - return; - } - - silc_client_init(silc_client); - - rec = g_new0(CHAT_PROTOCOL_REC, 1); - rec->name = "SILC"; - rec->fullname = "Secure Internet Live Conferencing"; - rec->chatnet = "silcnet"; - - rec->create_chatnet = create_chatnet; - rec->create_server_setup = create_server_setup; - rec->create_channel_setup = create_channel_setup; - rec->create_server_connect = create_server_connect; - - rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *)) - silc_server_connect; - rec->channel_create = - (CHANNEL_REC *(*) (SERVER_REC *, const char *, int)) - silc_channel_create; - rec->query_create = - (QUERY_REC *(*) (const char *, const char *, int)) - silc_query_create; - - chat_protocol_register(rec); - g_free(rec); - - silc_server_init(); - silc_channels_init(); - silc_queries_init(); - - idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL); + CHAT_PROTOCOL_REC *rec; + + static struct poptOption options[] = { + { "create-key-pair", 'C', POPT_ARG_NONE, &opt_create_keypair, 0, + "Create new public key pair", NULL }, + { "pkcs", 0, POPT_ARG_STRING, &opt_pkcs, 0, + "Set the PKCS of the public key pair", "PKCS" }, + { "bits", 0, POPT_ARG_INT, &opt_bits, 0, + "Set the length of the public key pair", "VALUE" }, + { "show-key", 'S', POPT_ARG_STRING, &opt_keyfile, 0, + "Show the contents of the public key", "FILE" }, + { NULL, '\0', 0, NULL } + }; + + args_register(options); + + if (opt_create_keypair == TRUE) { + /* Create new key pair and exit */ + silc_cipher_register_default(); + silc_pkcs_register_default(); + silc_hash_register_default(); + silc_hmac_register_default(); + silc_client_create_key_pair(opt_pkcs, opt_bits, + NULL, NULL, NULL, NULL, NULL); + silc_free(opt_pkcs); + exit(0); + } + + if (opt_keyfile == TRUE) { + /* Dump the key */ + silc_cipher_register_default(); + silc_pkcs_register_default(); + silc_hash_register_default(); + silc_hmac_register_default(); + silc_client_show_key(opt_keyfile); + silc_free(opt_keyfile); + exit(0); + } + + silc_client = silc_client_alloc(&ops, NULL); + silc_client->username = g_strdup(settings_get_str("user_name")); + silc_client->hostname = silc_net_localhost(); + silc_client->realname = g_strdup(settings_get_str("real_name")); + + if (!load_keys(silc_client)) { + idletag = -1; + return; + } + + silc_client_init(silc_client); + + rec = g_new0(CHAT_PROTOCOL_REC, 1); + rec->name = "SILC"; + rec->fullname = "Secure Internet Live Conferencing"; + rec->chatnet = "silcnet"; + rec->create_chatnet = create_chatnet; + rec->create_server_setup = create_server_setup; + rec->create_channel_setup = create_channel_setup; + rec->create_server_connect = create_server_connect; + rec->server_connect = (SERVER_REC *(*) (SERVER_CONNECT_REC *)) + silc_server_connect; + rec->channel_create = (CHANNEL_REC *(*) (SERVER_REC *, const char *, int)) + silc_channel_create; + rec->query_create = (QUERY_REC *(*) (const char *, const char *, int)) + silc_query_create; + + chat_protocol_register(rec); + g_free(rec); + + silc_server_init(); + silc_channels_init(); + silc_queries_init(); + + idletag = g_timeout_add(100, (GSourceFunc) my_silc_scheduler, NULL); } void silc_core_deinit(void) { - if (idletag != -1) { - signal_emit("chat protocol deinit", 1, - chat_protocol_find("SILC")); - - silc_server_deinit(); - silc_channels_deinit(); - silc_queries_deinit(); - - chat_protocol_unregister("SILC"); - - g_source_remove(idletag); - } - - g_free(silc_client->username); - g_free(silc_client->realname); - silc_client_free(silc_client); + if (idletag != -1) { + signal_emit("chat protocol deinit", 1, + chat_protocol_find("SILC")); + + silc_server_deinit(); + silc_channels_deinit(); + silc_queries_deinit(); + + chat_protocol_unregister("SILC"); + + g_source_remove(idletag); + } + + g_free(silc_client->username); + g_free(silc_client->realname); + silc_client_free(silc_client); } diff --git a/apps/irssi/src/silc/silc.c b/apps/irssi/src/silc/silc.c deleted file mode 100644 index de2bde07..00000000 --- a/apps/irssi/src/silc/silc.c +++ /dev/null @@ -1,4 +0,0 @@ -/* this file is automatically generated by configure - don't change */ -void silc_core_init(void); void silc_core_deinit(void); -void silc_init(void) { silc_core_init(); } -void silc_deinit(void) { silc_core_deinit(); } -- 2.24.0