Date: Mon, 20 Aug 2007 10:44:07 GMT From: Andrew Turner <andrew@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 125399 for review Message-ID: <200708201044.l7KAi7SW037615@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=125399 Change 125399 by andrew@andrew_hermies on 2007/08/20 10:43:08 Send a salt to the client to be used to check the password sent is correct Add an authenticate call. It accepts a password in the form sha256(sha256(password) + salt). Only when this is correct does it enable the other calls Ass a password dialog when connecting Set the correct attributes to a response when reading it in in the front end Affected files ... .. //depot/projects/soc2007/andrew-update/backend/facund-be.c#26 edit .. //depot/projects/soc2007/andrew-update/backend/freebsd-config-control.conf#2 edit .. //depot/projects/soc2007/andrew-update/frontend/facund-fe.glade#7 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/call.py#3 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/computer.py#15 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/gui/main_window.py#15 edit .. //depot/projects/soc2007/andrew-update/frontend/facund/network/__init__.py#15 edit .. //depot/projects/soc2007/andrew-update/lib/facund_connection.h#5 edit .. //depot/projects/soc2007/andrew-update/lib/facund_server.c#13 edit Differences ... ==== //depot/projects/soc2007/andrew-update/backend/facund-be.c#26 (text+ko) ==== @@ -74,6 +74,8 @@ static struct facund_response *facund_read_type_directory(const char *, const struct facund_object *, const char ***, int *, int *); +static struct facund_response *facund_call_authenticate(const char *, + struct facund_object *); static struct facund_response *facund_call_ping(const char *, struct facund_object *); static struct facund_response *facund_get_directories(const char *, @@ -123,7 +125,8 @@ static unsigned int watched_db_count = 0; static struct fbsd_update_db *watched_db = NULL; -struct utsname facund_uname; +static struct utsname facund_uname; +static char *password_hash = NULL; /* * Decodes the data in a line from the tag file @@ -517,6 +520,8 @@ facund_comms_in_loop = 0; } +static long facund_salt = 0; + static void * do_communication(void *data) { @@ -534,7 +539,11 @@ /* We are now in the loop. This will change on SIGPIPE */ facund_comms_in_loop = 1; - if(facund_server_start(conn) == -1) { + assert(facund_salt == 0); + do { + facund_salt = random(); + } while (facund_salt == 0); + if(facund_server_start(conn, facund_salt) == -1) { if (facund_in_loop != 0) { /* * When we are not quiting tell @@ -545,8 +554,10 @@ } break; } - if (facund_comms_in_loop == 0) + if (facund_comms_in_loop == 0) { + facund_salt = 0; continue; + } while(ret == 0) { ret = facund_server_get_request(conn); @@ -559,6 +570,7 @@ if (facund_comms_in_loop == 0) break; } + facund_salt = 0; if (facund_comms_in_loop == 0) continue; @@ -573,6 +585,40 @@ } static struct facund_response * +facund_call_authenticate(const char *id, struct facund_object *obj) +{ + char *buf, sum[65]; + + if (facund_salt == 0) { + return facund_response_new(id, 1, "Already authenticated",NULL); + } + if (facund_object_get_type(obj) != FACUND_STRING) { + return facund_response_new(id, 1, "Incorrect Data", NULL); + } + + /* Check the password */ + asprintf(&buf, "%s%ld", password_hash, facund_salt); + SHA256_Data(buf, strlen(buf), sum); + free(buf); + printf("%s\n%s\n\n", sum, facund_object_get_string(obj)); + if (strcmp(sum, facund_object_get_string(obj)) != 0) { + return facund_response_new(id, 1, "Incorrect Password", NULL); + } + + /* Add the callbacks for each call */ + facund_server_add_call("ping", facund_call_ping); + facund_server_add_call("get_directories", facund_get_directories); + facund_server_add_call("list_updates", facund_call_list_updates); + facund_server_add_call("list_installed", facund_call_list_installed); + facund_server_add_call("install_patches", facund_call_install_patches); + facund_server_add_call("rollback_patches",facund_call_rollback_patches); + facund_server_add_call("get_services", facund_call_get_services); + facund_server_add_call("restart_services",facund_call_restart_services); + + return facund_response_new(id, 0, "No Error", NULL); +} + +static struct facund_response * facund_call_ping(const char *id, struct facund_object *obj __unused) { struct facund_response *resp; @@ -1321,6 +1367,14 @@ errx(1, "Malloc failed"); } + password_hash = property_find(config_data, "password"); + if (password_hash != NULL) { + password_hash = strdup(password_hash); + if (password_hash == NULL) { + errx(1, "Malloc failed"); + } + } + properties_free(config_data); } @@ -1347,15 +1401,8 @@ sizeof facund_uname.release); } - /* Add the callbacks for each call */ - facund_server_add_call("ping", facund_call_ping); - facund_server_add_call("get_directories", facund_get_directories); - facund_server_add_call("list_updates", facund_call_list_updates); - facund_server_add_call("list_installed", facund_call_list_installed); - facund_server_add_call("install_patches", facund_call_install_patches); - facund_server_add_call("rollback_patches",facund_call_rollback_patches); - facund_server_add_call("get_services", facund_call_get_services); - facund_server_add_call("restart_services",facund_call_restart_services); + /* Only allow people to authenticate to begin with */ + facund_server_add_call("authenticate", facund_call_authenticate); pthread_create(&update_thread, NULL, look_for_updates, NULL); pthread_create(&comms_thread, NULL, do_communication, conn); ==== //depot/projects/soc2007/andrew-update/backend/freebsd-config-control.conf#2 (text+ko) ==== @@ -1,1 +1,5 @@ base_dirs = / + +; The password is "password". Change this with: +; ecgo -n password | sha256 +password = 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 ==== //depot/projects/soc2007/andrew-update/frontend/facund-fe.glade#7 (text+ko) ==== @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd"> -<!--Generated with glade3 3.2.2 on Mon Aug 20 10:28:13 2007 by andrew@hermies.int.fubar.geek.nz--> +<!--Generated with glade3 3.2.2 on Mon Aug 20 20:59:08 2007 by andrew@hermies.int.fubar.geek.nz--> <glade-interface> <widget class="GtkWindow" id="facundWindow"> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -110,34 +110,27 @@ <property name="column_spacing">5</property> <property name="row_spacing">5</property> <child> - <widget class="GtkButton" id="restartButton"> + <widget class="GtkButton" id="connectButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Restart</property> + <property name="label" translatable="yes">Connect</property> <property name="response_id">0</property> </widget> - <packing> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - </packing> </child> <child> - <widget class="GtkButton" id="deinstallButton"> + <widget class="GtkButton" id="disconnectButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Remove</property> + <property name="label" translatable="yes">Disconnect</property> <property name="response_id">0</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> </packing> </child> <child> @@ -155,28 +148,35 @@ </packing> </child> <child> - <widget class="GtkButton" id="disconnectButton"> + <widget class="GtkButton" id="deinstallButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Disconnect</property> + <property name="label" translatable="yes">Remove</property> <property name="response_id">0</property> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> </packing> </child> <child> - <widget class="GtkButton" id="connectButton"> + <widget class="GtkButton" id="restartButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Connect</property> + <property name="label" translatable="yes">Restart</property> <property name="response_id">0</property> </widget> + <packing> + <property name="right_attach">2</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> </child> </widget> <packing> @@ -276,27 +276,34 @@ <property name="column_spacing">3</property> <property name="row_spacing">10</property> <child> - <widget class="GtkLabel" id="label2"> + <widget class="GtkLabel" id="label3"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Computer's description +This is a Human redable +name for the computer</property> + </widget> + </child> + <child> + <widget class="GtkEntry" id="computerNameEntry"> <property name="visible">True</property> + <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Socket location -Leave blank for -the default socket</property> </widget> <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> </packing> </child> <child> - <widget class="GtkLabel" id="label1"> + <widget class="GtkEntry" id="computerEntry"> <property name="visible">True</property> + <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Computer's name -leave blank for the -local computer</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> </packing> @@ -315,37 +322,109 @@ </packing> </child> <child> - <widget class="GtkEntry" id="computerEntry"> + <widget class="GtkLabel" id="label1"> <property name="visible">True</property> - <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Computer's name +leave blank for the +local computer</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> </packing> </child> <child> - <widget class="GtkEntry" id="computerNameEntry"> + <widget class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Socket location +Leave blank for +the default socket</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + </packing> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <child> + <widget class="GtkButton" id="newConnectionSave"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">gtk-save</property> + <property name="use_stock">True</property> + <property name="response_id">0</property> + </widget> + </child> + <child> + <widget class="GtkButton" id="newConnectionCancel"> <property name="visible">True</property> <property name="can_focus">True</property> + <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="response_id">0</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="position">1</property> </packing> </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + </child> + </widget> + <widget class="GtkDialog" id="passwordDialog"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="border_width">5</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="has_separator">False</property> + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox2"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">2</property> + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <child> + <widget class="GtkLabel" id="label4"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Password:</property> + <property name="justify">GTK_JUSTIFY_RIGHT</property> + </widget> + </child> <child> - <widget class="GtkLabel" id="label3"> + <widget class="GtkEntry" id="passwordEntry"> <property name="visible">True</property> + <property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">Computer's description -This is a Human redable -name for the computer</property> + <property name="visibility">False</property> + <property name="activates_default">True</property> </widget> + <packing> + <property name="position">1</property> + </packing> </child> </widget> <packing> @@ -353,23 +432,23 @@ </packing> </child> <child internal-child="action_area"> - <widget class="GtkHButtonBox" id="dialog-action_area1"> + <widget class="GtkHButtonBox" id="dialog-action_area2"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="layout_style">GTK_BUTTONBOX_END</property> <child> - <widget class="GtkButton" id="newConnectionSave"> + <widget class="GtkButton" id="passwordOkButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">gtk-save</property> + <property name="label" translatable="yes">gtk-ok</property> <property name="use_stock">True</property> <property name="response_id">0</property> </widget> </child> <child> - <widget class="GtkButton" id="newConnectionCancel"> + <widget class="GtkButton" id="passwordCancelButton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> ==== //depot/projects/soc2007/andrew-update/frontend/facund/call.py#3 (text+ko) ==== @@ -65,7 +65,11 @@ def __str__(self): return "<response id=\"%s\" message=\"%s\" code=\"%s\">%s</response>" \ - % (self.__id, self.__message, self.__code, str(self.__data)) + % (self.__id, self.__message, self.__code, + str(self.__data or '')) def getData(self): return self.__data + + def getCode(self): + return self.__code ==== //depot/projects/soc2007/andrew-update/frontend/facund/computer.py#15 (text+ko) ==== @@ -24,8 +24,9 @@ # SUCH DAMAGE. # +import facund.network +import hashlib import socket -import facund.network import threading import types @@ -174,7 +175,7 @@ return call.getResponse() - def connect(self): + def connect(self, password): '''Connects to the remote computer''' if self.__connection is not None: return @@ -194,6 +195,22 @@ self.__connection.startLock.acquire() self.__connection.startLock.release() + # Authenticate with the server + salt = self.__connection.getSalt() + pass_hash = hashlib.sha256(password).hexdigest() + pass_hash = pass_hash + str(salt) + pass_hash = hashlib.sha256(pass_hash).hexdigest() + pass_hash = facund.String(pass_hash) + call = facund.Call("authenticate", pass_hash) + self.__connection.doCall(call) + call.acquireLock() + call.releaseLock() + # Disconnect if we failed to authenticate + if call.getResponse().getCode() != 0: + print call.getResponse().getCode() + self.disconnect() + return + # Get a list of directories the server offers call = facund.Call("get_directories", None) self.__connection.doCall(call) @@ -202,6 +219,7 @@ dirs = call.getResponse().getData().getData() for dir in dirs: self.addDir(dir.getData()) + except socket.error: print "Couldn't connect to %s " % (self.__host or self.__socket) del self.__connection ==== //depot/projects/soc2007/andrew-update/frontend/facund/gui/main_window.py#15 (text+ko) ==== @@ -60,6 +60,7 @@ menuItem.connect('activate', self.onQuit) self.__newConnectionDialog = None + self.__passwordDialog = None # Connect the signals to the new connection dialog box button = self.__xml.get_widget('newConnectionCancel') @@ -68,6 +69,13 @@ button = self.__xml.get_widget('newConnectionSave') button.connect('clicked', self.connectionSave) + # Connect the signals to the password dialog + button = self.__xml.get_widget('passwordOkButton') + button.connect('clicked', self.connectionStart) + + button = self.__xml.get_widget('passwordCancelButton') + button.connect('clicked', self.connectionCancel) + def onQuit(self, data): self.__controller.shutdown() @@ -186,17 +194,13 @@ def onConnectClick(self, widget): '''Signal handler for the connect button''' - #treeView = self.__xml.get_widget('computerView') - computer = self.__controller.getCurrentComputer() - computer.connect() - self.setConnected(computer.getConnectionStatus()) - self.__computerTreeModel.populateComputer(computer) + self.__passwordDialog = self.__xml.get_widget('passwordDialog') + self.__passwordDialog.show() self.setInstallable(False, False) def onDisconnectClick(self, widget): '''Signal handler for the connect button''' - #treeView = self.__xml.get_widget('computerView') computer = self.__controller.getCurrentComputer() computer.disconnect() self.setConnected(computer.getConnectionStatus()) @@ -205,6 +209,22 @@ # Disable the install/remove buttons self.setInstallable(False, False) + def connectionStart(self, widget): + password = self.__xml.get_widget('passwordEntry').get_text() + + computer = self.__controller.getCurrentComputer() + computer.connect(password) + self.setConnected(computer.getConnectionStatus()) + self.__computerTreeModel.populateComputer(computer) + + self.connectionCancel(widget) + + def connectionCancel(self, widget): + self.__passwordDialog.hide() + self.__passwordDialog = None + + self.__xml.get_widget('passwordEntry').set_text('') + def onInstallClick(self, widget): dir = self.__controller.getCurrentDirectory() self.__controller.installUpdates((dir.getName(), 'base')) ==== //depot/projects/soc2007/andrew-update/frontend/facund/network/__init__.py#15 (text+ko) ==== @@ -112,7 +112,6 @@ pass def doCall(self, call): - print call.getID() call.acquireLock() self.__calls[str(call.getID())] = call self.send(call.getCall()) @@ -123,6 +122,9 @@ def recv(self, len): return self.__connection.read(len) + def getSalt(self): + return self.__salt + def interact(self): '''Reads data from the connection and passes it to the XML parser''' @@ -136,8 +138,6 @@ return False def startElement(self, name, attributes): - print "> " + name + " " + str(attributes.items()) - if name == "data": data_type = None data = None @@ -166,23 +166,24 @@ self.__responseMessage = None self.__responseCode = None - for attr in attributes.items(): - if attr[0] == "id": - self.__responseID = int(attr[1]) - elif attr[0] == "code": - print self.__responseCode - elif attr[0] == "message": - self.__responseMessage = str(attr[1]) + for name, value in attributes.items(): + if name == "id": + self.__responseID = int(value) + elif name == "code": + self.__responseCode = int(value) + elif name == "message": + self.__responseMessage = str(value) else: print attr elif name == "facund-server": + for name, value in attributes.items(): + if name == 'salt': + self.__salt = int(value) self.__connected_lock.acquire() self.startLock.release() def endElement(self, name): - print "< " + name - if name == "data": data = self.__data.getParent() if data is not None: @@ -191,7 +192,7 @@ elif name == "response": response = facund.Response(self.__responseID, - self.__responseMessage, self.__responseCode, + self.__responseCode, self.__responseMessage, self.__data) # TODO: Check this is a valid item ==== //depot/projects/soc2007/andrew-update/lib/facund_connection.h#5 (text+ko) ==== @@ -43,7 +43,7 @@ void facund_close(struct facund_conn *); /* Server specific functions */ -int facund_server_start(struct facund_conn *); +int facund_server_start(struct facund_conn *, long); int facund_server_finish(struct facund_conn *); int facund_server_get_request(struct facund_conn *); ==== //depot/projects/soc2007/andrew-update/lib/facund_server.c#13 (text+ko) ==== @@ -55,9 +55,9 @@ * next it replys with the server start and returns */ int -facund_server_start(struct facund_conn *conn) +facund_server_start(struct facund_conn *conn, long salt) { - const char *str; + char *str; conn->close = 0; conn->parser = XML_ParserCreate(NULL); @@ -72,8 +72,17 @@ facund_server_end_tag); XML_SetCharacterDataHandler(conn->parser, facund_server_text); - str = "<facund-server version=\"0\">"; + if (salt == 0) { + str = strdup("<facund-server version=\"0\">"); + } else { + asprintf(&str, "<facund-server version=\"0\" salt=\"%ld\">", + salt); + } + if (str == NULL) { + return -1; + } facund_send(conn, str, strlen(str)); + free(str); return 0; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708201044.l7KAi7SW037615>